
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.List;

public class Client extends JFrame {
    DrawPane p;
    JButton btn = new JButton("清除");
    JButton circ = new JButton("圆形");
    JButton rect = new JButton("矩形");
    JButton line = new JButton("直线");
    JButton share = new JButton("开始共享");
    JButton stopShare = new JButton("结束共享");
    private String selectedShape = "LINE";
    private JTextArea userListTextArea; // Add a field for user list

    public Client(String name) {
        p = new DrawPane();
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS)); // 设置垂直布局
        buttonPanel.add(circ);
        buttonPanel.add(rect);
        buttonPanel.add(line);

        JPanel buttonPanel2 = new JPanel();
        buttonPanel2.setLayout(new BoxLayout(buttonPanel2, BoxLayout.Y_AXIS)); // 设置垂直布局
        buttonPanel2.add(share);
        buttonPanel2.add(stopShare);

        // 用户列表
        userListTextArea = new JTextArea();
        userListTextArea.setEditable(false);
        userListTextArea.setLineWrap(true);
        userListTextArea.setText("iuoyiuoyoiuyiu");
        userListTextArea.append("iuoyiuoyoiuyiu");

        JScrollPane scrollPane = new JScrollPane(userListTextArea);

        JPanel leftPanel = new JPanel();
        leftPanel.setLayout(new BorderLayout());
        leftPanel.add(buttonPanel, BorderLayout.WEST);
        leftPanel.add(scrollPane, BorderLayout.SOUTH);

        //以下连续几个皆是按钮的监听器
        btn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                selectedShape = "btn";
                p.updateSelectedShape(selectedShape);
                p.clearDrawing();
                p.repaint();
                try {
                    p.udpClient(selectedShape, 0, 0);
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        });
        // 添加形状的鼠标监听器
        circ.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                selectedShape = "CIRCLE";
                p.updateSelectedShape(selectedShape);
            }
        });

        rect.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                selectedShape = "RECTANGLE";
                p.updateSelectedShape(selectedShape);
            }
        });

        line.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                selectedShape = "LINE";
                p.updateSelectedShape(selectedShape);
            }
        });
        share.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                selectedShape = "SHARE";
                p.updateSelectedShape(selectedShape);
                try {
                    p.udpClient(selectedShape, 0, 0);
                    p.udpClient(name, 0, 0);
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        });
        stopShare.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                selectedShape = "STOPSHARE";
                p.updateSelectedShape(selectedShape);
                try {
                    p.udpClient(selectedShape, 0, 0);
                    p.udpClient(name, 0, 0, false);
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        });

        getContentPane().setLayout(new BorderLayout());
        getContentPane().add(p, "Center");
        getContentPane().add(btn, "North");
        getContentPane().add(leftPanel, "West"); // 设置在窗口的左边
        getContentPane().add(buttonPanel2, "East");
        setTitle("客户端画板");
        setSize(600, 400);
        setVisible(true);
    }

    // public static void main(String[] args) throws IOException {
    // new Client();
    // }
}

class DrawPane extends JPanel {
    private String selectedShape = "LINE";
//    private List<Shape> shapes = new ArrayList<>(); // 存储已绘制的图形
    private List<Shape> shapes = Collections.synchronizedList(new ArrayList<>());


    public void updateSelectedShape(String shape) {
        selectedShape = shape;
    }

    public DrawPane() {
        //鼠标监听器
        addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                int startX = e.getX();
                int startY = e.getY();
                int endX = startX;
                int endY = startY;

                Shape shape = null;
                try {
                    shape = createShape(startX, startY, endX, endY);
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }
                //加入鼠标按下时的坐标
                shapes.add(shape);
                repaint(); // 触发重新绘制
            }

            public void mouseReleased(MouseEvent e) {
                if (Objects.equals(selectedShape, "btn"))
                    System.out.println("btn");
                switch (selectedShape) {
                    case "CIRCLE":
                    case "RECTANGLE":
                    case "LINE":
                        try {
                            //当mouseReleased被触发，也就是鼠标松开时向服务器传endx与endy
                            udpClient(selectedShape, e.getX(), e.getY());
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                        break;
                }
            }
        });

        addMouseMotionListener(new MouseAdapter() {

            public void mouseDragged(MouseEvent e) {
                // 在鼠标拖动时更新线段的终点
                int endX = e.getX();
                int endY = e.getY();
                if (shapes != null && !shapes.isEmpty() && shapes.get(shapes.size() - 1) != null) {
                    shapes.get(shapes.size() - 1).updateShape(endX, endY);
                }
                repaint(); // 触发重新绘制
            }
        });
    }

    //根据四个数据创建相应形状的引用（形状由selectedShape判定）
    private Shape createShape(int startX, int startY, int endX, int endY) throws IOException {

        switch (selectedShape) {
            case "CIRCLE":

                try {
                    udpClient(selectedShape, startX, startY);
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                return new Circle(startX, startY, endX - startX, endY - startY);
            case "RECTANGLE":
                try {
                    udpClient(selectedShape, startX, startY);
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                return new Rectangle(startX, startY, endX - startX, endY - startY);
            case "LINE":
                try {
                    udpClient(selectedShape, startX, startY);
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                return new Line(startX, startY, endX, endY);
            default:
                return null;
        }
    }

    //清空画板
    public void clearDrawing() {
        shapes.clear();
        repaint();
    }


    @Override
    //遍历shapes，调用draw方法绘画
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        synchronized (shapes) {
            Iterator<Shape> iterator = shapes.iterator();
            while (iterator.hasNext()) {
                Shape shape = iterator.next();
                if (shape != null) {
                    shape.draw(g);
                }
            }
        }
    }

    //存形状对应startx,starty,endx,endy坐标的基类
    private interface Shape {
        void draw(Graphics g);

        void updateShape(int endX, int endY);
    }

    //三个形状的数据结构
    private static class Circle implements Shape {
        private int startX, startY, width, height;

        public Circle(int startX, int startY, int width, int height) {
            this.startX = startX;
            this.startY = startY;
            this.width = width;
            this.height = height;
        }

        @Override
        public void draw(Graphics g) {
            g.drawOval(startX, startY, width, height);
        }

        @Override
        public void updateShape(int endX, int endY) {
            width = endX - startX;
            height = endY - startY;
        }
    }

    private static class Rectangle implements Shape {
        private int startX, startY, width, height;

        public Rectangle(int startX, int startY, int width, int height) {
            this.startX = startX;
            this.startY = startY;
            this.width = width;
            this.height = height;
        }

        @Override
        public void draw(Graphics g) {
            g.drawRect(startX, startY, width, height);
        }

        @Override
        public void updateShape(int endX, int endY) {
            width = endX - startX;
            height = endY - startY;
        }
    }

    private static class Line implements Shape {
        private int startX, startY, endX, endY;

        public Line(int startX, int startY, int endX, int endY) {
            this.startX = startX;
            this.startY = startY;
            this.endX = endX;
            this.endY = endY;
        }

        @Override
        public void draw(Graphics g) {
            g.drawLine(startX, startY, endX, endY);
        }

        @Override
        public void updateShape(int endX, int endY) {
            this.endX = endX;
            this.endY = endY;
        }
    }


    //接下来是数据的发送、监听与处理
    //总的调用，一个发送一个监听
    public void udpClient(String button, int X, int Y) throws IOException {
        sendData(button,X,Y);
        //开新的线程用来监听
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    receiveData();
                    System.out.println("duoxiancheng");
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        thread.start();
    }
    //客户端的发送方法
    public void sendData(String button, int X, int Y) throws IOException {
        int port = 12000;// 服务器端口
        byte[] data;// 发送数据缓冲区
        DatagramPacket cPacket = null;
        MulticastSocket cSocket = null;
        InputStreamReader out = new InputStreamReader(System.in);
        BufferedReader in = new BufferedReader(out);
        InetAddress group = InetAddress.getByName("230.0.0.1");// 获取ip地址
        cSocket = join(group);
        data = (button + " " + String.valueOf(X) + " " + String.valueOf(Y)).getBytes(StandardCharsets.UTF_8);
        cPacket = new DatagramPacket(data, data.length, group, port);
        cSocket.send(cPacket);
        cSocket.close();
//        return  cSocket;
}
    //顾名思义，客户端的监听方法
    public void receiveData() throws IOException {
        int receivePort = 13000;
        InetAddress group = InetAddress.getByName("230.0.0.1");// 获取ip地址
        MulticastSocket cSocket2 = join(group, receivePort);
        // 接收的包
        DatagramPacket receivePacket = null;
        byte[] receive = new byte[1000];
        String cin, cin2 = null;
        int startX, startY = 0, endX = 0, endY = 0;
        receivePacket = new DatagramPacket(receive, receive.length);
        while (true) {
            try {
                cSocket2.receive(receivePacket);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            cin = new String(receivePacket.getData(), 0, receivePacket.getLength());

            System.out.println(cin);

            StringTokenizer scin = new StringTokenizer(cin, " ");
            String orderStr = scin.nextToken();// 接受指令
            String X1 = scin.nextToken();
            startX = Integer.parseInt(X1);
            if (scin.hasMoreElements()) {
                String Y1 = scin.nextToken();
                startY = Integer.parseInt(Y1);
            }
            String orderStr2 = null;
            if (!Objects.equals(orderStr, "btn")) {
                try {
                    cSocket2.receive(receivePacket);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                cin2 = new String(receivePacket.getData(), 0, receivePacket.getLength());

                System.out.println(cin2);

                StringTokenizer scin2 = new StringTokenizer(cin2, " ");
                orderStr2 = scin2.nextToken();// 接受指令
                String X2 = scin2.nextToken();
                endX = Integer.parseInt(X2);
                String Y2 = scin2.nextToken();
                endY = Integer.parseInt(Y2);
            }

            switch (orderStr) {
                case "CIRCLE":
                    Circle circle = new Circle(startX, startY, endX - startX, endY - startY);
                    shapes.add(circle);
                    repaint();
                    System.out.println("传过来了！！");
                    break;
            }
        }
    }
    //结束共享时用的，主要是leavegroup
    public void udpClient(String button, int X, int Y, boolean joinOrLeave) throws IOException {
        if (!joinOrLeave) {
            int port = 12000;// 服务器端口
            byte[] data;// 发送数据缓冲区
            DatagramPacket cPacket = null;
            MulticastSocket cSocket = null;
            InputStreamReader out = new InputStreamReader(System.in);
            BufferedReader in = new BufferedReader(out);
            InetAddress group = InetAddress.getByName("230.0.0.1");// 获取ip地址
            cSocket = join(group);
            data = (button + " " + String.valueOf(X) + " " + String.valueOf(Y)).getBytes(StandardCharsets.UTF_8);
            cPacket = new DatagramPacket(data, data.length, group, port);
            cSocket.send(cPacket);
            cSocket.leaveGroup(group);
        }
    }

    public MulticastSocket join(InetAddress group) throws IOException {
        try{
            MulticastSocket cSocket = new MulticastSocket();
            cSocket.joinGroup(group);
            return cSocket;
        } catch (IOException e){
            e.printStackTrace();
        }
        System.out.println("iuyiuyiuy");
        return null;
    }

    //我定义客户端监听端口为13000，对应端口joingroup
    public MulticastSocket join(InetAddress group, int port) throws IOException {
        try{
            MulticastSocket cSocket = new MulticastSocket(port);
            cSocket.joinGroup(group);
            return cSocket;
        } catch (IOException e){
            e.printStackTrace();
        }
        System.out.println("iuyiuyiuy");
        return null;
    }
}
